package clientService;

import java.io.*;
import java.io.ObjectInputStream.GetField;
import java.net.*;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import javax.swing.table.TableColumn;

import serverExceptions.ParseException;
import serverService.MessageParser;

import domain.ClientMessage;
import domain.MessageType;
import domain.Stock;
import domain.TypeOfOrder;

public class ClientApp {
	private static Socket serverSocket;
	private static PrintWriter outert;
	private static BufferedReader in;
	private static String user;
	private static String servRespons = "";
	private static LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();

	public static void main(String... args) {

		init("localhost", 5090);
		sendMessage("35=A|49=he|");
		sendMessage("35=D|49=he|11=|55=BTR|54=2|38=30|40=<>|44=35.9|");
		sendMessage("35=D|49=he|11=|55=BTR|54=1|38=30|40=<>|44=45.9|");

		while (true) {

			try {
				System.out.println(in.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

	}

	static void sendMessage(final String msg) {
		Thread thread = new Thread(new Runnable() {
			public void run() {

				System.out.println("Writing: " + msg);
				outert.println(msg);
				outert.flush();
				System.out.println("client>" + msg);

			}
		});

		thread.start();

	}

	public static String login(String userName) {

		ClientMessage message = new ClientMessage();
		message.setMessageType(MessageType.LOGON);
		message.setSenderCompID(userName);
		sendMessage(message.toString());

		try {
			String servRespons = in.readLine();
			System.out.println("server " + servRespons);
			try {
				MessageType messType = MessageParser
						.getMessageType(servRespons);
				switch (messType) {
				case LOGON:
					user = MessageParser.getSenderCompID(servRespons);
					return new String("Login as: " + user);
				case Reject:
					return new String(MessageParser.getText(servRespons));
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String newOrder(String stock, String amount, String price,
			String type) {

		ClientMessage mess = new ClientMessage();

		mess.setMessageType(MessageType.NewOrderSingle);
		mess.setStock(Stock.parse(stock));
		mess.setSenderCompID(user);
		mess.setClOrdID(10);
		mess.setAmount(Integer.parseInt(amount));
		mess.setPrice(Double.parseDouble(price));
		mess.setOrderType(TypeOfOrder.parse(Integer.parseInt(type)));
		sendMessage(mess.toString());

		return recieveMessage();
	}

	public static boolean isAck(String message) {
		MessageType messType;
		try {
			messType = MessageParser.getMessageType(message);
			switch (messType) {
			case Execution_Report:
				switch (MessageParser.getExType(message)) {
				case 0:
					return true;
				}
			default:
				return false;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}

	public static boolean isFilled(String message) {
		synchronized (servRespons) {
			MessageType messType;
			try {
				messType = MessageParser.getMessageType(message);
				switch (messType) {
				case Execution_Report:
					switch (MessageParser.getExType(message)) {
					case 2:
						return true;
					}
				default:
					return false;
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}
			return false;
		}
	}

	public String getLoginMessage() {
		recieveMessage();
		synchronized (messageQueue) {
			servRespons = messageQueue.poll();
			System.out.println("server> " + servRespons);
			try {
				MessageType messType = MessageParser
						.getMessageType(servRespons);
				switch (messType) {
				case LOGON:
					return servRespons;
				default:
					messageQueue.add(servRespons);
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}
			return null;
		}
	}

	public static String recieveMessage() {
		synchronized (servRespons) {
			try {
				servRespons = in.readLine();
				if (isAck(servRespons)) {
					return new String("Order Added: "
							+ MessageParser.getStock(servRespons) + " "
							+ MessageParser.getOrdQntity(servRespons) + " "
							+ MessageParser.getPrice(servRespons));
				}
				if (isFilled(servRespons)) {
					return new String("Order Matched: "
							+ MessageParser.getStock(servRespons) + " "
							+ MessageParser.getOrdQntity(servRespons) + " "
							+ MessageParser.getPrice(servRespons));
				}
			} catch (IOException | ParseException e) {
				e.printStackTrace();
			}
		}
		return servRespons;
	}

	public static String init(String server, int port) {
		try {
			serverSocket = new Socket(server, port);
		} catch (IOException e) {
			e.printStackTrace();
			return new String("Connection Failed");
		}
		try {
			outert = new PrintWriter(new OutputStreamWriter(
					serverSocket.getOutputStream()));
			in = new BufferedReader(new InputStreamReader(
					serverSocket.getInputStream()));
		} catch (IOException e) {
			e.printStackTrace();
			return new String("Connection Failed");
		}
		return ("Connected to " + serverSocket.getInetAddress() + ":" + serverSocket
				.getLocalPort());
	}
}
